package main

import (
	"fmt"
	"github.com/golang-jwt/jwt/v4"
	"strings"
	"time"
)

// 定义 JWT 密钥，必须与生成 Token 时使用的密钥完全一致
var jwtSecret = []byte("your-secret-key-32bytes")

// 定义一个函数，用于生成登录凭证（JWT）
// 参数 userID 是用户的唯一标识，例如 "user_10086" 或数据库中的用户 ID
// 返回值是生成的 JWT 字符串
func generateLoginToken(userID string) string {
	// 定义 JWT 的 Claims（载荷）
	// Claims 是一个 JSON 对象，包含了要传输的信息
	claims := jwt.MapClaims{
		"user_id": userID,                               // 自定义字段：用户 ID
		"exp":     time.Now().Add(2 * time.Hour).Unix(), // 标准字段：过期时间（Expiration Time）
		// 你还可以添加其他自定义字段，例如：
		// "role": "admin",      // 用户角色
		// "username": "张三"    // 用户名
	}

	// 创建一个新的 Token 对象
	// jwt.SigningMethodHS256 指定了使用 HMAC-SHA256 算法进行签名
	// claims 是我们刚刚定义的载荷
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 使用密钥对 Token 进行签名
	// 这是最关键的一步！密钥必须严格保密，绝不能泄露给客户端
	// 如果密钥泄露，任何人都可以伪造 Token
	signedToken, err := token.SignedString(jwtSecret)
	if err != nil {
		// 在实际应用中，这里应该有错误处理逻辑
		panic("生成 Token 失败: " + err.Error())
	}

	// 返回签名后的 Token 字符串
	return signedToken
}

// verifyToken 验证 Token 的有效性，并返回用户 ID
// 如果验证失败，返回空字符串和错误信息
func verifyToken(tokenString string) (string, error) {
	// 解析 Token
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// 验证签名算法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("不支持的签名算法: %v", token.Header["alg"])
		}
		return jwtSecret, nil
	})

	if err != nil {
		return "", err
	}

	// 检查 Token 是否有效
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		// 从 Claims 中提取 user_id
		userID, ok := claims["user_id"].(string)
		if !ok {
			return "", fmt.Errorf("Token 中 user_id 字段无效")
		}
		return userID, nil
	}

	return "", fmt.Errorf("Token 无效或已过期")
}

func main() {
	// 模拟用户登录成功后，调用函数生成 Token
	fmt.Println("--- 步骤 1: 用户登录，生成 Token ---")
	userID := "user_10086" // 假设这是登录用户的 ID
	token := generateLoginToken(userID)
	fmt.Printf("生成的 Token: %s\n\n", token)

	// 打印生成的 Token
	fmt.Println("用户", userID, "登录成功！")
	fmt.Println("生成的登录凭证（JWT）：")
	fmt.Println(token)
	fmt.Println("\n前端收到此 Token 后，应将其存储起来（如 localStorage）。")
	fmt.Println("后续请求时，在 HTTP 请求头中携带此 Token，例如：")
	fmt.Println("Authorization: Bearer", token)

	// 模拟一段时间后，用户发送请求
	fmt.Println("--- 步骤 2: 前端发送请求，携带 Token ---")
	// 假设前端在请求头中携带了 Token
	// 格式通常是 "Bearer <token>"
	authHeader := fmt.Sprintf("Bearer %s", token)
	fmt.Printf("前端请求头中的 Authorization: %s\n\n", authHeader)

	fmt.Println("--- 步骤 3: 后端验证 Token ---")
	// 后端从请求头中提取 Token
	// 这里我们手动模拟这个过程
	parts := strings.Split(authHeader, " ")
	if len(parts) != 2 || parts[0] != "Bearer" {
		fmt.Println("登录失败: Token 格式错误")
		return
	}
	receivedToken := parts[1]

	// 调用验证函数
	validatedUserID, err := verifyToken(receivedToken)
	if err != nil {
		fmt.Printf("登录失败: %v\n", err)
	} else {
		fmt.Printf("登录成功！欢迎回来，用户: %s\n", validatedUserID)
		// 在这里可以执行后续的业务逻辑，比如查询用户信息、返回受保护的数据等
	}

	fmt.Println("\n--- 模拟 Token 过期或无效的情况 ---")
	// 假设一个无效的 Token
	invalidToken := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MTYyMzkwMjIsInVzZXJfaWQiOiJ1c2VyXzEwMDg2In0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
	authHeaderInvalid := fmt.Sprintf("Bearer %s", invalidToken)
	fmt.Printf("携带无效 Token 的请求头: %s\n", authHeaderInvalid)

	partsInvalid := strings.Split(authHeaderInvalid, " ")
	receivedTokenInvalid := partsInvalid[1]
	validatedUserIDInvalid, errInvalid := verifyToken(receivedTokenInvalid)
	if errInvalid != nil {
		fmt.Printf("登录失败: %v\n", errInvalid)
	} else {
		fmt.Printf("登录成功！欢迎回来，用户: %s\n", validatedUserIDInvalid)
	}
}
